#!/usr/bin/env python3
"""Auto-generate API documentation Markdown files.

• Backend(admin) endpoints   -> 后台管理api接口详细说明文档.md
• Mini-program(user) endpoints -> 前台小程序api接口详细说明文档.md

The script walks through all Flask routes, extracts:
    - URL rule & HTTP methods
    - View function docstring (first line) as plain explanation
    - If Flask-RESTX model attached via @expect, list its fields (+description)
    - If validate_required_fields(...) found, treat those as required JSON fields
    - Basic request.args/get_json key detection (heuristic, may need manual polish)

This produces a Markdown skeleton which can be manually refined.
"""
from __future__ import annotations

import re
import inspect
import textwrap
from pathlib import Path
from typing import Dict, List, Set

import sys, os
BASE_DIR = Path(__file__).resolve().parent
sys.path.append(str(BASE_DIR / 'backend'))

from app import create_app
import flask_restx as _frx

# -------------------------------------
# Helpers
# -------------------------------------

FIELD_RE = re.compile(r"request\.get_json\(\)[^\n]*?\.get\(\s*'([^']+)'")
ARGS_RE = re.compile(r"request\.args\.get\(\s*'([^']+)'")
VALIDATE_REQ_RE = re.compile(r"validate_required_fields\(\[([^\]]+)\]")
SPLIT_QUOTE_RE = re.compile(r"'([^']+)'")


def extract_parameters(source: str) -> Dict[str, Set[str]]:
    """Rudimentary parameter extraction from source code."""
    json_params = set(FIELD_RE.findall(source))
    query_params = set(ARGS_RE.findall(source))
    # required fields list inside validate_required_fields(['a','b'])
    required = set()
    for group in VALIDATE_REQ_RE.findall(source):
        required.update(SPLIT_QUOTE_RE.findall(group))
    return {
        "json": json_params,
        "query": query_params,
        "required": required,
    }


def classify_endpoint(url: str) -> str:
    """Return 'backend' or 'mini'"""
    if url.startswith("/admin/") or url.startswith("/api/files/admin"):
        return "backend"
    # treat everything else as mini-program side
    return "mini"


def main():
    app = create_app()

    backend_lines: List[str] = [
        "# 后台管理 API 接口详细说明文档",
        "",
        "*自动生成，仅供参考；如需调整请人工修改*",
        "",
    ]
    mini_lines: List[str] = [
        "# 前台小程序 API 接口详细说明文档",
        "",
        "*自动生成，仅供参考；如需调整请人工修改*",
        "",
    ]

    for rule in sorted(app.url_map.iter_rules(), key=lambda r: r.rule):
        if rule.rule.startswith("/static"):
            continue
        methods = ", ".join(sorted(rule.methods - {"HEAD", "OPTIONS"}))
        endpoint = rule.endpoint
        view_func = app.view_functions[endpoint]

        # Get original function if wrapped (flask_restx wraps methods)
        func_obj = getattr(view_func, "__wrapped__", view_func)

        doc = inspect.getdoc(func_obj) or "无"
        first_line = doc.strip().split("\n")[0] if doc else "无"

        source = inspect.getsource(func_obj)
        params = extract_parameters(source)

        param_lines: List[str] = []
        if params["query"]:
            param_lines.append("**Query 参数**：" + ", ".join(sorted(params["query"])))
        if params["json"]:
            param_lines.append("**JSON 参数**：" + ", ".join(sorted(params["json"])))
        if params["required"]:
            param_lines.append("**必填字段**：" + ", ".join(sorted(params["required"])))
        if not param_lines:
            param_lines.append("无明显参数（或待补充）")

        # gather model-defined params
        model_fields: List[str] = []
        if hasattr(func_obj, '__apidoc__'):
            apidoc = func_obj.__apidoc__ or {}
            expect_models = apidoc.get('expect', [])
            for model in expect_models:
                # model may be (Model, ...) tuple in restx 0.5+ ; ensure we get first element
                if isinstance(model, tuple):
                    model = model[0]
                if isinstance(model, _frx.model.Model):
                    for fname, field in model.items():
                        desc = getattr(field, 'description', '') or ''
                        required = getattr(field, 'required', False)
                        model_fields.append(f"{fname}{'(*)' if required else ''}:{desc}")
        if model_fields:
            param_lines.append("**Model 字段**：" + ", ".join(model_fields))

        section = [
            f"### {rule.rule}",
            f"- **方法**：{methods}",
            f"- **大白话**：{first_line}",
            "- **请求参数**：",
        ]
        section.extend(["  - " + line for line in param_lines])
        section.append("- **返回**：待补充")
        section.append("")

        if classify_endpoint(rule.rule) == "backend":
            backend_lines.extend(section)
        else:
            mini_lines.extend(section)

    # Write files
    Path("后台管理api接口详细说明文档.md").write_text("\n".join(backend_lines), encoding="utf-8")
    Path("前台小程序api接口详细说明文档.md").write_text("\n".join(mini_lines), encoding="utf-8")
    print("🎉 API 文档已自动生成/更新完成！")


if __name__ == "__main__":
    main() 